#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <sys/un.h> 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/tcp.h>

#include "estructuras.h"
#include "constantes.h"
#include "sockets.h"


struct sockaddr_in cargarSocketInet(char *ip,int puerto){
    
    struct sockaddr_in sin;
     
    sin.sin_family = AF_INET;         
    sin.sin_port = htons(puerto);  
    sin.sin_addr.s_addr =INADDR_ANY; 
    
    return sin;
      
}

struct sockaddr_un cargarSocketUNIX(char* path_Socket){
  
    struct sockaddr_un local;
    
    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, path_Socket);
    unlink(local.sun_path);
    
    return local;

}


int crearSocket(int tipo){
	
    int sock;															  
    
    switch(tipo){
    
	case AF_INET:
	
	    if((sock = socket(tipo,SOCK_STREAM,0)) == -1){   
		return ERRORCREARSOCKETINET;														  
	    }
		
	    break;
	
	case AF_UNIX:
	    
	    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
		return ERRORCREARSOCKETUNIX;
	    }  
	    
	    break;    
    }
    
	int optval = 1;
    setsockopt(sock, IPPROTO_TCP,TCP_NODELAY, &optval, sizeof(optval));
	
    return sock;

    
}

int escuchar (int socket, int clientesEnCola){
    
    if (listen(socket,clientesEnCola) == -1){
	return ERRORLISTEN;
    }
 
}


int aceptarConexion(int sock){
   
   struct sockaddr_in * cliente;
   int descriptorCliente;
   int address_size=sizeof(struct sockaddr_in);
 
    if((descriptorCliente = accept(sock,(struct sockaddr*)&cliente,&address_size))== -1) 
		return ERRORACCEPT;		 
    
 
    return descriptorCliente;
}
 
int conectarINET(int sock,struct sockaddr_in sin){	
      
    if (connect(sock,(struct sockaddr*)&sin,sizeof(sin))==-1)
	return ERRORCONECTARINET;

    return sock;
}

int conectarUNIX(int sock,struct sockaddr_un sun,int len){	
      
    if (connect(sock,(struct sockaddr*)&sun,len)==-1)
	return ERRORCONECTARUNIX;

    return sock;
}


int cerrarSocket(int sock){
    
    if(close(sock) == -1){							
	    return ERRORCLOSE;
    }
    
    return EXITO;
}


int conectarAServidorINET(struct sockaddr_in pin){						  
	
   int sock;
	
   sock = crearSocket(AF_INET);

    if(connect(sock, (struct sockaddr*)&pin, sizeof(pin)) == -1){
	
	close(sock);
	return ERRORCONECTARASERVIDORINET;
	
    }
    
    return sock;

    
}


int crearSocketEscuchaINET(struct sockaddr_in sin){						  
    
    int sock;
    sock = crearSocket(AF_INET);

    if(bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1){
	close(sock);
	return ERRORBIND;
    }
    return sock;
}

int bindSocketUnix(int socket,struct sockaddr_un local){
    
    int len;
    
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    
    if (bind(socket, (struct sockaddr *)&local, len) == -1) {
	return ERRORBIND;
    }
      
}


int Conectar (int socket, char *ip, int puerto)
{
    struct sockaddr_in sin;

    sin=cargarSocketInet(ip,puerto);
    conectarAServidorINET(sin);
    
}



int PrepararSocket(int puertoLocal, char *ipLocal)
{
    int iDescriptor_del_socket; 
    struct sockaddr_in sin;
    int sock;

     
    sin.sin_family = AF_INET;         
    sin.sin_port = htons(puertoLocal);  
    sin.sin_addr.s_addr =INADDR_ANY; 
	
   
    sock = crearSocket(AF_INET);

    if(bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1){
      close(sock);
      return ERRORBIND;
    }
    
    
    return sock;
}




int CrearYConectarDosSockets(int* iDescriptor1, int*iDescriptor2, char * sIP_local)
{

    struct sockaddr_in Str_sockaddr_in_paraAcept;
    int iSocketEscucha_temporal;
    int ipuertoAleatorio = 6000;	
    int iDescriptor_del_socket; 
    struct sockaddr_in sin;
    int iAddress_size = sizeof ( struct sockaddr_in );

   * iDescriptor1 = crearSocket(AF_INET);
   
    sin.sin_family = AF_INET;         
    sin.sin_port = htons(ipuertoAleatorio);  
    sin.sin_addr.s_addr =INADDR_ANY; 
	
   iSocketEscucha_temporal = crearSocket(AF_INET);

    if(bind(iSocketEscucha_temporal, (struct sockaddr*)&sin, sizeof(sin)) == -1){
      close(iSocketEscucha_temporal);
      return ERRORBIND;
    }
   
    escuchar (iSocketEscucha_temporal,1);
    Conectar2( *iDescriptor1 , sIP_local , ipuertoAleatorio  ) ;
  	*iDescriptor2 = accept ( iSocketEscucha_temporal , ( struct sockaddr * ) &Str_sockaddr_in_paraAcept , &iAddress_size ); 
    cerrarSocket(iSocketEscucha_temporal);

    return 0;
}




int Conectar2 ( int iDescriptor_del_socket , char* sIP_remoto , int iPuerto_remoto_para_el_socket )
{
	struct sockaddr_in Str_sockaddr_in_paraConnect;/*estructura para el Connect*/

	Str_sockaddr_in_paraConnect.sin_family = AF_INET;/*estructura para el connect*/
	Str_sockaddr_in_paraConnect.sin_addr.s_addr = inet_addr (sIP_remoto);
	Str_sockaddr_in_paraConnect.sin_port = htons (iPuerto_remoto_para_el_socket);	
	memset (&(Str_sockaddr_in_paraConnect.sin_zero), 8, '\0');
	
	
	if ( connect ( iDescriptor_del_socket , (struct sockaddr *) & Str_sockaddr_in_paraConnect , sizeof (Str_sockaddr_in_paraConnect ) ) == -1 )/*conect & check*/
       {

		printf("error al conectar\n");

		return -1;
            }
	else
            {

		return 5;
            }
}






/*
int CrearYConectarDosSockets(int* iDescriptor1, int* iDescriptor2, char * sIP_local ,char * sDescripcion1)
{

struct sockaddr_in Str_sockaddr_in_paraAcept;
int iAddress_size = sizeof ( struct sockaddr_in );
int iSocketEscucha_temporal;
char sPuertoAleatorio[10]="\0";
int	 iPuertoAleatorio;	
	
	*iDescriptor1 = PrepararSocket ( "NULL" , sIP_local , sDescripcion1 );
        if(*iDescriptor1 < 0)
            return -1;

	iPuertoAleatorio = GenerarNumero(1024 , 65536 , sPuertoAleatorio , *iDescriptor1);			//genera un puerto al azar entre 1024 y 65535, usa como semilla el iDescriptor

	iSocketEscucha_temporal = PrepararSocket ( sPuertoAleatorio , sIP_local , "Socket temporal para escuchar conexion" );
        if(iSocketEscucha_temporal < 0)
            return -1;

	Escuchar (iSocketEscucha_temporal, 1);

	if(Conectar( *iDescriptor1 , sIP_local , iPuertoAleatorio  ) == -1)
            return -1;

	*iDescriptor2 = accept ( iSocketEscucha_temporal , ( struct sockaddr * ) &Str_sockaddr_in_paraAcept , &iAddress_size ); 

	Cerrar(iSocketEscucha_temporal);

	return 0;
}

*/

int GenerarNumero(int Minimo, int Maximo,int n)
{
    int Numero;
    time_t tiempo;

    tiempo = time(NULL);
    srand ((unsigned int) tiempo+n );
    Numero = Minimo + (rand() % (Maximo - Minimo));

    return Numero;
}
	